﻿using System;
using System.ComponentModel.Composition;
using Cubicle.Core.Interfaces;

namespace Cubicle.Core.Processors.Construct
{
    [Export("Cubicle.Processors.Construct.DoubleArrayConstructProcessor", typeof(IProcessor<InstructionRequest>))]
    [ExportMetadata("Name", "DoubleArrayConstructProcessor")]
    [ExportMetadata("Description", "Creates jagged arrays")]
    public class DoubleArrayConstructProcessor : InstructionRequestProcessor
    {

        public DoubleArrayConstructProcessor() : base(RequestType.CustomConstruct) { }

        public override bool Condition(InstructionRequest request)
        {
            return base.Condition(request)
                && request.TargetType.IsArray
                && request.TargetType.GetArrayRank() == 2
                && !request.TargetType.GetElementType().IsArray;
        }

        public override InstructionRequest ConditionalProcess(InstructionRequest request)
        {
            // Find array type
            var elementType = request.TargetType.GetElementType();

            // Find size of first dimension
            var parameters = request.Inst.Parameters;
            var dimLength1 = parameters.GetLength(0);

            // Find size of second dimension
            int dimLength2 = 0;
            for (int dim1 = 0; dim1 < dimLength1; dim1++)
            {
                var arr = (Array) parameters[dim1];
                dimLength2 = Math.Max(arr.Length, dimLength2);
            }

            // Construct double array
            var result = Array.CreateInstance(elementType, dimLength1, dimLength2);

            // Initialise double array
            for (int dim1 = 0; dim1 < dimLength1; dim1++)
            {
                var arr = (Array)parameters[dim1];
                for (int dim2 = 0; dim2 < dimLength2; dim2++)
                    result.SetValue(Convert.ChangeType(arr.GetValue(dim2), elementType), dim1, dim2);
            }

            // Return result
            request.Complete(result);
            return request;
        }

    }
}